package com.hyw.trace.configuration.meta.http;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.StreamUtils;

/**
 * 创建一个线程安全的HTTP日志打印拦截器
 * 
 * @author hongyu
 */
public class LoggingRequestInterceptor implements ClientHttpRequestInterceptor {

  private static final Logger log = LoggerFactory.getLogger(LoggingRequestInterceptor.class);

  @Override
  public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution)
      throws IOException {
    ClientHttpResponse response = execution.execute(request, body);
    return log(request, body, response);
  }

  private ClientHttpResponse log(final HttpRequest request, final byte[] body, final ClientHttpResponse response)
      throws IOException {
    final ClientHttpResponse responseCopy = new BufferingClientHttpResponseWrapper(response);
    StringBuilder sb = new StringBuilder();
    sb.append("\n");
    sb.append("URI         : {0} \n");
    sb.append("Method      : {1} \n");
    sb.append("Headers     : {2} \n");
    sb.append("Request body: {3} \n");
    sb.append("Response status code: {4} \n");
    sb.append("Response body:{5} \n");
    String logText = MessageFormat.format(sb.toString(), request.getURI(), request.getMethod(), request.getHeaders(),
        new String(body, StandardCharsets.UTF_8), responseCopy.getStatusCode().value(),
        StreamUtils.copyToString(responseCopy.getBody(), StandardCharsets.UTF_8));
    log.info(logText);
    return responseCopy;
  }

  private final class BufferingClientHttpResponseWrapper implements ClientHttpResponse {

    private final ClientHttpResponse response;

    private byte[] body;

    BufferingClientHttpResponseWrapper(ClientHttpResponse response) {
      this.response = response;
    }

    @Override
    public HttpStatus getStatusCode() throws IOException {
      return this.response.getStatusCode();
    }

    @Override
    public int getRawStatusCode() throws IOException {
      return this.response.getRawStatusCode();
    }

    @Override
    public String getStatusText() throws IOException {
      return this.response.getStatusText();
    }

    @Override
    public HttpHeaders getHeaders() {
      return this.response.getHeaders();
    }

    @Override
    public InputStream getBody() throws IOException {
      if (this.body == null) {
        this.body = StreamUtils.copyToByteArray(this.response.getBody());
      }
      return new ByteArrayInputStream(this.body);
    }

    @Override
    public void close() {
      this.response.close();
    }
  }

}
